package cn.sylinx.hbatis.ext.mirage.repository;

import java.util.List;
import java.util.Map;

import cn.sylinx.hbatis.db.common.Page;
import cn.sylinx.hbatis.db.common.Record;
import cn.sylinx.hbatis.ext.common.BaseConst;
import cn.sylinx.hbatis.ext.common.repository.CommonDaoServiceImpl;
import cn.sylinx.hbatis.ext.mirage.spi.MirageServiceManager;
import cn.sylinx.hbatis.ext.parse.SqlParser;
import cn.sylinx.hbatis.ext.res.ClasspathSqlResource;
import cn.sylinx.hbatis.kit.Tuple;

public class DaoServiceImpl extends CommonDaoServiceImpl implements DaoService {

	private BaseRepository baseRepository;

	public DaoServiceImpl() {
	}

	public DaoServiceImpl(BaseRepository baseRepository) {
		super(baseRepository);
		this.baseRepository = baseRepository;
	}

	public BaseRepository getBaseRepository() {
		return baseRepository;
	}

	public void setBaseRepository(BaseRepository baseRepository) {
		this.baseRepository = baseRepository;
	}

	private ClasspathSqlResource createClasspathSqlResource(String sqlResource) {
		ClasspathSqlResource resource = new ClasspathSqlResource(sqlResource);
		resource.setStatementHandler(getStatementHandler());
		return resource;
	}

	@Override
	public Object updateWithReturnPk(String sqlResource, Map<String, Object> params) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return updateWithReturnPk(resource, params);
	}

	@Override
	public Object updateWithReturnPk(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.updateWithReturnPk(resource, params);
	}

	@Override
	public boolean execute(String sqlResource) {
		return execute(sqlResource, null);
	}

	@Override
	public boolean execute(String sqlResource, Map<String, Object> params) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return execute(resource, params);
	}

	@Override
	public boolean execute(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.execute(resource, params);
	}

	@Override
	public int update(String sqlResource, Map<String, Object> params) {

		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return update(resource, params);
	}

	@Override
	public int update(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.update(resource, params);
	}

	@Override
	public int update(String sqlResource) {
		return update(sqlResource, null);
	}

	@Override
	public int delete(String sqlResource, Map<String, Object> params) {

		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return delete(resource, params);
	}

	@Override
	public int delete(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.delete(resource, params);
	}

	@Override
	public int delete(String sqlResource) {
		return delete(sqlResource, (Map<String, Object>) null);
	}

	@Override
	public <T> List<T> queryList(String sqlResource, Map<String, Object> params, Class<T> clz) {

		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryList(resource, params, clz);
	}

	@Override
	public <T> List<T> queryList(ClasspathSqlResource resource, Map<String, Object> params, Class<T> clz) {
		return baseRepository.queryList(resource, params, clz);
	}

	@Override
	public <T> List<T> queryObjectList(String sqlResource, Map<String, Object> params, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return baseRepository.queryObjectList(resource, params, clz);
	}

	@Override
	public <T> T queryFirstObject(String sqlResource, Map<String, Object> params, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return baseRepository.queryFirstObject(resource, params, clz);
	}

	@Override
	public <T> T queryFirst(String sqlResource, Map<String, Object> params, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryFirst(resource, params, clz);
	}

	@Override
	public <T> List<T> queryObjectListWithCache(String sqlResource, Map<String, Object> params, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return MirageServiceManager.getMirageService().useService(baseRepository.getDatabase()).withMirageCache()
				.queryObjectList(resource, params, clz);
	}

	@Override
	public <T> T queryFirstObjectWithCache(String sqlResource, Map<String, Object> params, Class<T> clz) {
		List<T> dataList = queryObjectListWithCache(sqlResource, params, clz);
		return dataList.isEmpty() ? null : dataList.get(0);
	}

	@Override
	public <T> T queryFirst(ClasspathSqlResource resource, Map<String, Object> params, Class<T> clz) {
		return baseRepository.queryFirst(resource, params, clz);
	}

	@Override
	public Record queryRecord(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.queryRecord(resource, params);
	}

	@Override
	public <T> List<T> queryList(String sqlResource, Class<T> clz) {
		return queryList(sqlResource, null, clz);
	}

	@Override
	public <T> T queryFirst(String sqlResource, Class<T> clz) {
		return queryFirst(sqlResource, null, clz);
	}

	@Override
	public Record queryRecord(String sqlResource, Map<String, Object> params) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryRecord(resource, params);
	}

	@Override
	public Record queryRecord(String sqlResource) {
		return queryRecord(sqlResource, null);
	}

	@Override
	public List<Record> queryRecords(String sqlResource, Map<String, Object> params) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryRecords(resource, params);
	}

	@Override
	public List<Record> queryRecords(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.queryRecords(resource, params);
	}

	@Override
	public List<Record> queryRecords(String sqlResource) {
		return queryRecords(sqlResource, null);
	}

	private Tuple getQuerySqlAndParams(String sqlResource, Map<String, Object> params) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return SqlParser.parseSql(resource, params);
	}

	@Override
	public <T> Page<T> queryPage(String sqlResource, int pageNumber, int pageSize, Map<String, Object> params,
			Class<T> clz) {

		Tuple tp = getQuerySqlAndParams(sqlResource, params);

		String preSql = (String) tp.get(0);
		Object[] prePms = (Object[]) tp.get(1);

		Tuple t = getDialect().getSqlBuilder().buildPaginatorSql(preSql, pageNumber, pageSize);
		String sqlCount = t.getObject(0);
		Record r = baseRepository.queryRecord(sqlCount, prePms);
		int totalRow = r == null ? 0 : Integer.valueOf(r.get("totalCount").toString());
		if (totalRow == 0) {
			// 空
			Page<T> emptyPage = new Page<T>();
			emptyPage.setPageSize(pageSize);
			return emptyPage;
		}

		int totalPage = (int) (totalRow / pageSize);
		if (totalRow % pageSize != 0) {
			totalPage++;
		}

		String sqlLimit = t.getObject(1);
		Object[] pms = t.getObject(2);

		int paramSize = prePms == null ? 0 : prePms.length;
		int pageParamSize = pms == null ? 0 : pms.length;
		int finalParamSize = paramSize + pageParamSize;
		Object[] finalParams = new Object[finalParamSize];

		// 查询参数
		if (paramSize > 0) {
			for (int i = 0; i < paramSize; ++i) {
				finalParams[i] = prePms[i];
			}
		}

		// 分页参数
		if (pageParamSize > 0) {
			for (int i = 0; i < pageParamSize; ++i) {
				finalParams[i + paramSize] = pms[i];
			}
		}

		List<T> dataList = baseRepository.queryList(sqlLimit, clz, finalParams);
		Page<T> page = new Page<T>(dataList, pageNumber, pageSize, totalPage, totalRow);
		return page;
	}

	@Override
	public <T> Page<T> queryPage(String sqlResource, int pageNumber, Map<String, Object> params, Class<T> clz) {
		return queryPage(sqlResource, pageNumber, BaseConst.DEFAULT_PAGE_SIZE_16, params, clz);
	}

	@Override
	public <T> Page<T> queryPage(String sqlResource, int pageNumber, Class<T> clz) {
		return queryPage(sqlResource, pageNumber, null, clz);
	}

	@Override
	public <T> Page<T> queryPage(String sqlResource, int pageNumber, int pageSize, Class<T> clz) {
		return queryPage(sqlResource, pageNumber, pageSize, null, clz);
	}

	@Override
	public Page<Record> queryPageRecords(String sqlResource, int pageNumber, int pageSize, Map<String, Object> params) {

		Tuple tp = getQuerySqlAndParams(sqlResource, params);

		String preSql = (String) tp.get(0);
		Object[] prePms = (Object[]) tp.get(1);

		Tuple t = getDialect().getSqlBuilder().buildPaginatorSql(preSql, pageNumber, pageSize);
		String sqlCount = t.getObject(0);
		Record r = baseRepository.queryRecord(sqlCount, prePms);
		int totalRow = r == null ? 0 : Integer.valueOf(r.get("totalCount").toString());
		if (totalRow == 0) {
			// 空
			Page<Record> emptyPage = new Page<Record>();
			emptyPage.setPageSize(pageSize);
			return emptyPage;
		}

		int totalPage = (int) (totalRow / pageSize);
		if (totalRow % pageSize != 0) {
			totalPage++;
		}

		String sqlLimit = t.getObject(1);
		Object[] pms = t.getObject(2);

		int paramSize = prePms == null ? 0 : prePms.length;
		int pageParamSize = pms == null ? 0 : pms.length;
		int finalParamSize = paramSize + pageParamSize;
		Object[] finalParams = new Object[finalParamSize];

		// 查询参数
		if (paramSize > 0) {
			for (int i = 0; i < paramSize; ++i) {
				finalParams[i] = prePms[i];
			}
		}

		// 分页参数
		if (pageParamSize > 0) {
			for (int i = 0; i < pageParamSize; ++i) {
				finalParams[i + paramSize] = pms[i];
			}
		}

		List<Record> dataList = baseRepository.queryRecords(sqlLimit, finalParams);
		Page<Record> page = new Page<Record>(dataList, pageNumber, pageSize, totalPage, totalRow);
		return page;
	}

	@Override
	public Page<Record> queryPageRecords(String sqlResource, int pageNumber, Map<String, Object> params) {
		return queryPageRecords(sqlResource, pageNumber, BaseConst.DEFAULT_PAGE_SIZE_16, params);
	}

	@Override
	public Page<Record> queryPageRecords(String sqlResource, int pageNumber) {
		return queryPageRecords(sqlResource, pageNumber, null);
	}

	@Override
	public Page<Record> queryPageRecords(String sqlResource, int pageNumber, int pageSize) {
		return queryPageRecords(sqlResource, pageNumber, pageSize, (Map<String, Object>) null);
	}

	@Override
	public <T> List<T> queryListWithCache(String sqlResource, Map<String, Object> params, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryListWithCache(resource, params, clz);
	}

	@Override
	public <T> List<T> queryListWithCache(ClasspathSqlResource resource, Map<String, Object> params, Class<T> clz) {
		return baseRepository.queryListWithCache(resource, params, clz);
	}

	@Override
	public <T> T queryFirstWithCache(String sqlResource, Map<String, Object> params, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryFirstWithCache(resource, params, clz);
	}

	@Override
	public <T> T queryFirstWithCache(ClasspathSqlResource resource, Map<String, Object> params, Class<T> clz) {
		return baseRepository.queryFirstWithCache(resource, params, clz);
	}

	@Override
	public <T> List<T> queryListWithCache(String sqlResource, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return baseRepository.queryListWithCache(resource, clz);
	}

	@Override
	public <T> T queryFirstWithCache(String sqlResource, Class<T> clz) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return baseRepository.queryFirstWithCache(resource, clz);
	}

	@Override
	public Record queryRecordWithCache(String sqlResource, Map<String, Object> params) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryRecordWithCache(resource, params);
	}

	@Override
	public Record queryRecordWithCache(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.queryRecordWithCache(resource, params);
	}

	@Override
	public Record queryRecordWithCache(String sqlResource) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return baseRepository.queryRecordWithCache(resource);
	}

	@Override
	public List<Record> queryRecordsWithCache(String sqlResource, Map<String, Object> params) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return queryRecordsWithCache(resource, params);
	}

	@Override
	public List<Record> queryRecordsWithCache(ClasspathSqlResource resource, Map<String, Object> params) {
		return baseRepository.queryRecordsWithCache(resource, params);
	}

	@Override
	public List<Record> queryRecordsWithCache(String sqlResource) {
		ClasspathSqlResource resource = createClasspathSqlResource(sqlResource);
		return baseRepository.queryRecordsWithCache(resource);
	}

}
